﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;
using System.Xml.Serialization;

namespace Konves.Scripture.Data
{
    internal class Repository
    {
        internal Repository()
        {
            using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(@"Konves.Scripture.Data.esv.xml"))
            {
                XmlSerializer s = new XmlSerializer(typeof(Version.ScriptureResource));
                this._resource = (Version.ScriptureResource)s.Deserialize(stream);
            }
        }

        private Version.ScriptureResource _resource;

        internal int GetBookId(string abbr)
        {
            var book = _resource.Books.FirstOrDefault(b => b.Abbreviations.Select(a => a.ToLower()).Contains(abbr.Trim().ToLower()));

            if (book == null)
                throw new ArgumentOutOfRangeException("abbr");
            else
                return book.Number;
        }

        internal string GetBookName(string abbr)
        {
            var book = _resource.Books.FirstOrDefault(b => b.Abbreviations.Select(a => a.ToLower()).Contains(abbr.Trim().ToLower()));

            if (book == null)
                throw new ArgumentOutOfRangeException("abbr");
            else
                return book.Name;
        }

        internal int GetMaxChapter(int bookId)
        {
            var limits = _resource.ChapterLimits.Where(l => l.BookNumber == bookId);

            if (limits == null || !limits.Any())
                throw new ArgumentOutOfRangeException("bookId");
            else
                return limits.Max(l => l.ChapterNumber);
        }

        internal int GetMaxVerse(int bookId, int chapter)
        {
            var limits = _resource.ChapterLimits.FirstOrDefault(l => l.BookNumber == bookId && l.ChapterNumber == chapter);

            if (limits == null)
                throw new ArgumentOutOfRangeException();
            else
                return limits.EndVerseNumber;
        }

        internal void GetVerseData(int bookId, int chapter, int verse, out int index, out int chapterResult, out int verseResult)
        {
            var limits = _resource.ChapterLimits.FirstOrDefault(l => l.BookNumber == bookId && l.ChapterNumber == chapter);

            if (limits == null)
            {
                index = -1;
                chapterResult = -1;
                verseResult = -1;
            }
            else
            {
                index = limits.StartVerseIndex + verse;
                chapterResult = limits.ChapterNumber;
                verseResult = verse;
            }
        }

        internal BookInfo GetBookInfo(string abbr)
        {
            // TODO: Edit for clarity
            var x = _resource.Books.FirstOrDefault(b => b.Abbreviations.Select(a => a.ToLower()).Concat(new string[] { b.Name.ToLower() }).Contains(abbr.Trim().ToLower()));

            if (x == null)
                return null;
            else
                return new BookInfo
                {
                    Id = x.Number,
                    Name = x.Name
                };
        }

        internal BookInfo GetBookInfo(int bookId)
        {
            var x = _resource.Books.FirstOrDefault(b => b.Number == bookId);

            if (x == null)
                return null;
            else
                return new BookInfo
                {
                    Id = x.Number,
                    Name = x.Name
                };
        }
    }
}
